package com.yisoo.ubag.iot.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.iot.model.v20180120.*;
import com.yisoo.common.constant.LoginStatusConstant;
import com.yisoo.common.constant.RedisStringConstant;
import com.yisoo.common.to.BoxRelBagTo;
import com.yisoo.common.to.CheckDeviceIsOpenTo;
import com.yisoo.common.to.DevSimpleDataTo;
import com.yisoo.common.utils.R;
import com.yisoo.common.vo.DeviceDetailVo;
import com.yisoo.ubag.iot.aliyun.sdk.openapi.DeviceManager;
import com.yisoo.ubag.iot.aliyun.sdk.openapi.PubManager;
import com.yisoo.ubag.iot.constant.TopicConstant;
import com.yisoo.ubag.iot.entity.DevRelOrderEntity;
import com.yisoo.ubag.iot.entity.ProdEntity;
import com.yisoo.ubag.iot.service.BoxRelBagService;
import com.yisoo.ubag.iot.service.ProdService;
import com.yisoo.ubag.iot.util.MqttDataMapping;
import com.yisoo.ubag.iot.vo.DeviceStatusMqttContentVo;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yisoo.common.utils.PageUtils;
import com.yisoo.common.utils.Query;

import com.yisoo.ubag.iot.dao.DeviceDao;
import com.yisoo.ubag.iot.entity.DeviceEntity;
import com.yisoo.ubag.iot.service.DeviceService;
import org.springframework.transaction.annotation.Transactional;


@Service("deviceService")
public class DeviceServiceImpl extends ServiceImpl<DeviceDao, DeviceEntity> implements DeviceService {

    @Autowired
    ProdService prodService;
    @Autowired
    DevRelOrderServiceImpl devRelOrderService;
    @Autowired
    BoxRelBagService boxRelBagService;
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Override
    public PageUtils queryPage(Map<String, Object> params) {

        Long cid = Long.valueOf((String)params.get("cid"));
        String productKey = prodService.getById(cid).getProductKey();
        QueryWrapper<DeviceEntity> queryWrapper = new QueryWrapper<>();

        queryWrapper.eq("product_key",productKey);

        IPage<DeviceEntity> page = this.page(
                new Query<DeviceEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    @Override
//    @Transactional
    public R batchAdd(Long cid, List<DevSimpleDataTo> datas) {


        List<String> names = datas.stream().map(DevSimpleDataTo::getDevName).collect(Collectors.toList());
        //查询出product
        ProdEntity prodEntity = prodService.getById(cid);
        String productKey = prodEntity.getProductKey();
        //获取批量注册的许可
//        public static BatchCheckDeviceNamesResponse.Data batchCheckDeviceNames(String productKey, List<String> deviceNames) {
        BatchCheckDeviceNamesResponse.Data checkResult = DeviceManager.batchCheckDeviceNames(productKey, names);

//        查询结果
        QueryBatchRegisterDeviceStatusResponse.Data deviceStatus = DeviceManager.queryBatchRegisterDeviceStatus(productKey,checkResult.getApplyId());

//        System.out.println("】】】】】】"+deviceStatus.getStatus());
        BatchRegisterDeviceWithApplyIdResponse.Data resData;
        if (deviceStatus.getStatus().equals("CREATE_SUCCESS")){
            resData = DeviceManager.batchRegisterDeviceWithApplyId(productKey, checkResult.getApplyId());
//            校验请求并把数据存入数据库
//            this.saveResult(productKey,checkResult.getApplyId(),datas.size(),datas);
        }else{
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                deviceStatus = DeviceManager.queryBatchRegisterDeviceStatus(productKey,checkResult.getApplyId());
                resData = DeviceManager.batchRegisterDeviceWithApplyId(productKey, checkResult.getApplyId());
            }
        }

        List<DeviceEntity> collect = datas.stream().map(temp -> {
            DeviceEntity deviceEntity = new DeviceEntity();
            deviceEntity.setDevId(temp.getDevId());
            deviceEntity.setDeviceName(temp.getDevName());
            deviceEntity.setProductKey(productKey);
            return deviceEntity;
        }).collect(Collectors.toList());
        this.saveBatch(collect);


        //完成批量注册
        //发起完全性请求将数据持久化到数据库
        this.saveResult(productKey,cid,collect);

        return  R.ok().put("data",resData);
    }

    @Override
    public R reload(Long cid) {
        //根据cid获取productkey
        String productKey = prodService.getById(cid).getProductKey();
//        查出信息不全的设备
        QueryWrapper<DeviceEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("product_key",productKey);
        List<DeviceEntity> selectList = baseMapper.selectList(queryWrapper);


        List<DeviceEntity> collect = selectList.stream().filter(temp -> {
            if (temp.getDeviceSecret() == null) {
                return true;
            } else {
                return false;
            }
        }).collect(Collectors.toList());
        if (collect.size() == 0) return R.ok("无需刷新");
        List<String> names = collect.stream().map(DeviceEntity::getDeviceName).collect(Collectors.toList());
        List<BatchQueryDeviceDetailResponse.DataItem> dataItems = DeviceManager.batchQueryDeviceDetail(productKey, names);

        List<DeviceEntity> collectResult = collect.stream().map(temp -> {
            DeviceEntity deviceEntity = new DeviceEntity();
            BeanUtils.copyProperties(temp, deviceEntity);
            for (BatchQueryDeviceDetailResponse.DataItem item : dataItems) {
                if (deviceEntity.getDeviceName().equals(item.getDeviceName())) {
                    deviceEntity.setIotId(item.getIotId());
                    deviceEntity.setDeviceSecret(item.getDeviceSecret());
                    deviceEntity.setDeviceStatus(item.getStatus());
                    return deviceEntity;
                }
            }
            return deviceEntity;
        }).collect(Collectors.toList());

        this.saveOrUpdateBatch(collectResult);
        return R.ok();
    }

    @Override
    public R updateStatus(Long cid) {
        //根据cid获取productkey
        String productKey = prodService.getById(cid).getProductKey();
//        查出信息不全的设备
        QueryWrapper<DeviceEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("product_key",productKey);
        List<DeviceEntity> selectList = baseMapper.selectList(queryWrapper);


        List<String> names = selectList.stream().map(DeviceEntity::getDeviceName).collect(Collectors.toList());
        List<BatchQueryDeviceDetailResponse.DataItem> dataItems = DeviceManager.batchQueryDeviceDetail(productKey, names);

        List<DeviceEntity> collectResult = selectList.stream().map(temp -> {
            DeviceEntity deviceEntity = new DeviceEntity();
            BeanUtils.copyProperties(temp, deviceEntity);
            for (BatchQueryDeviceDetailResponse.DataItem item : dataItems) {
                if (deviceEntity.getDeviceName().equals(item.getDeviceName())) {
                    deviceEntity.setIotId(item.getIotId());
                    deviceEntity.setDeviceSecret(item.getDeviceSecret());
                    deviceEntity.setDeviceStatus(item.getStatus());
                    return deviceEntity;
                }
            }
            return deviceEntity;
        }).collect(Collectors.toList());

        this.saveOrUpdateBatch(collectResult);
        return R.ok();
    }

    @Override
    public R detail(Long did) {
        DeviceEntity deviceEntity = this.getById(did);
        String productKey = deviceEntity.getProductKey();
        String deviceName = deviceEntity.getDeviceName();
        List<String> names = new ArrayList<>();
        names.add(deviceName);
        List<BatchQueryDeviceDetailResponse.DataItem> dataItems = DeviceManager.batchQueryDeviceDetail(productKey, names);
        DeviceDetailVo detailVo = new DeviceDetailVo();
        BeanUtils.copyProperties(dataItems.get(0),detailVo);

        return R.ok().put("data",detailVo);

    }

    @Override
    public void updateOne(DeviceStatusMqttContentVo content) {
        DeviceEntity deviceEntity = getDev(content.getProductKey(), content.getDeviceName());
        deviceEntity.setDeviceStatus(content.getStatus().toUpperCase());
        baseMapper.updateById(deviceEntity);
    }

    @Override
    public DeviceEntity getDev(String productKey, String devName) {
        QueryWrapper<DeviceEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("product_key",productKey).eq("device_name",devName);
        return baseMapper.selectList(queryWrapper).get(0);
    }

    @Override
    public DeviceEntity getDevByName(String devName) {
        QueryWrapper<DeviceEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("device_name",devName);
        return baseMapper.selectList(queryWrapper).get(0);
    }

//    @Override
//    public R openBoxTest(String devSecret) {
//        QueryWrapper<DeviceEntity> queryWrapper = new QueryWrapper<>();
//        queryWrapper.eq("device_secret",devSecret);
//        DeviceEntity e = baseMapper.selectOne(queryWrapper);
//        if(e == null){
//            return R.error("devSecret不存在");
//        }else{
//            if(e.getDeviceStatus().equals("ONLINE")){
//                Integer checkOpen = devRelOrderService.checkBagUsing(e);
//                if (checkOpen == 1){
//                    return R.error("背包已经开启");
//                }else if(checkOpen == 2){
//                    return R.error("背包被锁定，请联系管理员");
//                }else if(checkOpen == 0){
//                    //可以打开
//                    //发送开启背包请求，设备回复开启状态
////                    (String content,String productKey,
////                            String topic,Integer qos)
//                    String content = MqttDataMapping.getDataPack(101);
//                    System.out.println(content);
//                    PubManager.PubRequest(
//                            content,
//                            e.getProductKey(),
//                            TopicConstant.getTopicString(e.getProductKey(),e.getDeviceName(),TopicConstant.SubOrder),
//                            0
//                    );
//                    return R.ok();
//                }
//            }else if(e.getDeviceStatus().equals("OFFLINE")){
//                return R.error("设备不在线");
//            }else if(e.getDeviceStatus().equals("UNACTIVE")){
//                return R.error("设备未激活");
//            }else{
//                return R.error("状态异常");
//            }
//        }
//        return null;
//    }

    //检查背包是否可以打开 ，如果可以 则储存uuid 并返回uuid，用户通过UUID打开锁
    @Override
    public CheckDeviceIsOpenTo check(String devSecret) {
        //获取存储箱设备
        DeviceEntity deviceEntity = getDevBySecret(devSecret);

        if(deviceEntity == null){
//            找不到设备
            return new CheckDeviceIsOpenTo(CheckDeviceIsOpenTo
                    .CheckDeviceStatus.DEVICE_NULL,"");
        }else{
//            根据设备状态处理
            switch (deviceEntity.getDeviceStatus()) {
//               存储箱在线
                case "ONLINE":
//                    检查存储箱中是否有背包
                    Integer bagId = boxRelBagService.boxIsHaveBag(deviceEntity.getDevId());
                    if (bagId == -1) {
                        return new CheckDeviceIsOpenTo(CheckDeviceIsOpenTo
                                .CheckDeviceStatus.DEVICE_NO_BAG, "");
                    } else {
                        //检查存储箱中的背包是否在线
                        DeviceEntity temp = baseMapper.selectById(bagId);
                        if(temp.getDeviceStatus().equals("ONLINE")){
                            //背包也在线，现在检查背包是否可用，防止被别人开了
                            //背包在线状态
                            Integer checkOpen = devRelOrderService.checkBagUsing(deviceEntity.getDevId(),bagId);
                            if (checkOpen == 0) {
                                //背包未打开
                                //现在可以用了
                                String uuid = UUID.randomUUID().toString().replace("-", "");
                                BoxRelBagTo boxRelBagTo = new BoxRelBagTo(deviceEntity.getDevId(), bagId.longValue());
                                //存入缓存
                                stringRedisTemplate.opsForValue().set(RedisStringConstant.OPEN_BOX_UUID+uuid, JSON.toJSONString(boxRelBagTo),60*5, TimeUnit.SECONDS);
                                return new CheckDeviceIsOpenTo(CheckDeviceIsOpenTo
                                        .CheckDeviceStatus.DEVICE_OK, uuid,deviceEntity.getDevId(),bagId.longValue());
                            } else if (checkOpen == 1) {
//                    背包已经打开了
                                return new CheckDeviceIsOpenTo(CheckDeviceIsOpenTo
                                        .CheckDeviceStatus.DEVICE_OPENED, "");
                            } else if (checkOpen == 2) {
                                //背包状态异常
                                return new CheckDeviceIsOpenTo(CheckDeviceIsOpenTo
                                        .CheckDeviceStatus.DEVICE_STATUS_ERROR, "");
                            }
                        }else{
                            return new CheckDeviceIsOpenTo(CheckDeviceIsOpenTo
                                    .CheckDeviceStatus.DEVICE_BAG_STATUS_ERROR, "");
                        }
                    }
                    break;
//                    存储箱不在线
                case "OFFLINE":
                    return new CheckDeviceIsOpenTo(CheckDeviceIsOpenTo
                            .CheckDeviceStatus.DEVICE_OFFLINE, "");
                case "UNACTIVE":
//                    存储箱未激活
                    return new CheckDeviceIsOpenTo(CheckDeviceIsOpenTo
                            .CheckDeviceStatus.DEVICE_UNACTIVE, "");
                default:
                    return new CheckDeviceIsOpenTo(CheckDeviceIsOpenTo
                            .CheckDeviceStatus.DEVICE_STATUS_ERROR, "");
            }
        }
        return null;
    }

    @Override
    public DeviceEntity getDevBySecret(String devSecret) {
        QueryWrapper<DeviceEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("device_secret",devSecret);
        return baseMapper.selectOne(queryWrapper);
    }

    @Override
    public R open(String bagId) {
        //修改数据库字段
        DevRelOrderEntity devRelOrderEntity = devRelOrderService.getById(bagId);
        if(devRelOrderEntity.getIsUsing() == 0){
            //可以用
            //发送到硬件
//            System.out.println("发送到硬件");
            //                    (String content,String productKey,
//                            String topic,Integer qos)
            DeviceEntity e = baseMapper.selectById(devRelOrderEntity.getDevId());
            String content = MqttDataMapping.getDataPack(101);
//            System.out.println(content);
            PubManager.PubRequest(
                    content,
                    e.getProductKey(),
                    TopicConstant.getTopicString(e.getProductKey(),e.getDeviceName(),TopicConstant.SubOrder),
                    0
            );
            //TODO：开启背包汇报自己名字的开关
            //修改数据库字段
            devRelOrderEntity.setIsUsing(1);
            devRelOrderEntity.setBuyNum(devRelOrderEntity.getBuyNum()+1);
            devRelOrderEntity.setDevId((long) -1);
            devRelOrderService.updateById(devRelOrderEntity);


            return R.ok("成功打开");
        }else{
            return R.error("背包已经打开");
        }

    }
    @Override
    public R close(String bagId) {
        //修改数据库字段
        DevRelOrderEntity devRelOrderEntity = devRelOrderService.getById(bagId);
        if(devRelOrderEntity.getIsUsing() == 1){
            //可以用
            //修改数据库字段
            devRelOrderEntity.setIsUsing(0);
            Long devId = boxRelBagService.getEntityByBagId(bagId);
            devRelOrderEntity.setDevId(devId);
            devRelOrderService.updateById(devRelOrderEntity);
            //发送到硬件
//            System.out.println("发送到硬件");
            //                    (String content,String productKey,
//                            String topic,Integer qos)
            DeviceEntity e = baseMapper.selectById(devId);
            String content = MqttDataMapping.getDataPack(102);
//            System.out.println(content);
            PubManager.PubRequest(
                    content,
                    e.getProductKey(),
                    TopicConstant.getTopicString(e.getProductKey(),e.getDeviceName(),TopicConstant.SubOrder),
                    0
            );
            return R.ok("成功打开");
        }else{
            return R.error("背包已经打开");
        }

    }

    @Override
    public R testMapping(Long bagId, Integer control) {
        DeviceEntity e = baseMapper.selectById(bagId);
        String content = MqttDataMapping.getDataPack(control);
            System.out.println(">>>" + content);
        if(control == 101){
            stringRedisTemplate.opsForValue().set(RedisStringConstant.BAG_OPEN_OR_CLOSE +bagId, JSONObject.toJSONString(1),60*10,TimeUnit.SECONDS);
        }
        else if(control == 102){
            stringRedisTemplate.opsForValue().set(RedisStringConstant.BAG_OPEN_OR_CLOSE +bagId, JSONObject.toJSONString(0),60*10,TimeUnit.SECONDS);
        }else if (control == 203){
            stringRedisTemplate.opsForValue().set(RedisStringConstant.BAG_WU_OPEN_OR_CLOSE +bagId, JSONObject.toJSONString(1),60*10,TimeUnit.SECONDS);
        }else if(control == 204){
            stringRedisTemplate.opsForValue().set(RedisStringConstant.BAG_WU_OPEN_OR_CLOSE +bagId, JSONObject.toJSONString(0),60*10,TimeUnit.SECONDS);
        }
        PubManager.PubRequest(
                content,
                e.getProductKey(),
                TopicConstant.getTopicString(e.getProductKey(),e.getDeviceName(),TopicConstant.SubOrder),
                0
        );
        return R.ok();
    }
//    @Override
//    public R testOpen(String bagId) {
//        //修改数据库字段
//        //可以打开
//        //发送开启背包请求，设备回复开启状态
////                    (String content,String productKey,
////                            String topic,Integer qos)
//        Long devId = devRelOrderService.getById(bagId).getDevId();
//        DeviceEntity e = baseMapper.selectById(devId);
//        String content = MqttDataMapping.getDataPack(101);
//        System.out.println(content);
//        PubManager.PubRequest(
//                content,
//                e.getProductKey(),
//                TopicConstant.getTopicString(e.getProductKey(),e.getDeviceName(),TopicConstant.SubOrder),
//                0
//        );
//        System.out.println("发送到硬件");
//        return R.ok();
//    }


    //    @Async
    public void saveResult(String productKey, Long cid, List<DeviceEntity> datas) {

        List<String> nameList = datas.stream().map(DeviceEntity::getDeviceName).collect(Collectors.toList());

        List<BatchQueryDeviceDetailResponse.DataItem> dataItems = DeviceManager.batchQueryDeviceDetail(productKey, nameList);

        List<DeviceEntity> collect = datas.stream().map(temp -> {
            DeviceEntity deviceEntity = new DeviceEntity();
            BeanUtils.copyProperties(temp, deviceEntity);
            for (BatchQueryDeviceDetailResponse.DataItem item : dataItems) {
                if (deviceEntity.getDeviceName().equals(item.getDeviceName())) {
                    deviceEntity.setIotId(item.getIotId());
                    deviceEntity.setDeviceSecret(item.getDeviceSecret());
                    deviceEntity.setDeviceStatus(item.getStatus());
                    return deviceEntity;
                }
            }
            return deviceEntity;
        }).collect(Collectors.toList());

        this.saveOrUpdateBatch(collect);
//        //查询结果
//        QueryBatchRegisterDeviceStatusResponse.Data deviceStatus = DeviceManager.queryBatchRegisterDeviceStatus(productKey,applyId);
//        if (deviceStatus.getStatus().equals("CREATE")){
//            //处理成功
//            List<QueryPageByApplyIdResponse.ApplyDeviceInfo> deviceInfos = DeviceManager.queryPageByApplyId(applyId, size, 1);
////            private String deviceId;
////            private String deviceName;
////            private String deviceSecret;
////            private String iotId;
//
//            List<DeviceEntity> collect = deviceInfos.stream().map(temp -> {
//                DeviceEntity deviceEntity = new DeviceEntity();
//                deviceEntity.setDevId(Long.valueOf("0"));
//                for (DevSimpleDataTo t : dids) {
//                    if (temp.getDeviceName().equals(t.getDevName())) {
//                        deviceEntity.setDeviceName(temp.getDeviceName());
//                        deviceEntity.setProductKey(productKey);
//                        deviceEntity.setDeviceStatus("OFFLINE");
//                        deviceEntity.setDeviceSecret(temp.getDeviceSecret());
//                        deviceEntity.setIotId(temp.getIotId());
//                        deviceEntity.setDevId(t.getDevId());
//                        return deviceEntity;
//                    }
//                }
//                return deviceEntity;
//            }).collect(Collectors.toList());
//
//            this.saveBatch(collect);
//        }else{
//            //处理失败
//            System.out.println("创建失败");
//        }
    }

}